<?php
/*
 * Copyright (c) 2009 Tom Smith (tom@takeontom.com).
 * 
 * Distributed under the terms of the GNU Lesser General Public License.
 * 
 * ---------------------------------------------------------------------------------
 * 
 * This file is part of Seraph PHP Framework.
 *
 * Seraph PHP Framework is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Seraph PHP Framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Seraph PHP Framework.  If not, see <http://www.gnu.org/licenses/>.
*/


class Framework	{
	
	protected $rootPath;
	
	protected $config;
	
	protected $includeAutoloader;
	
	protected $viewResourceContainer;
	
	public function __construct()	{
		$this->setupRootPath();
	}
	
	/**
	 * Initialise the framework
	 * @return unknown_type
	 */
	public function boot()	{	
		$this->setupAutoloader();
		$this->setupConfig();
		$this->setupDB();
		$this->setupModel();
	}
	
	/**
	 * Set the root path to the framework root
	 */
	protected function setupRootPath()	{
		$this->rootPath = realpath(dirname(__FILE__));
	}
	
	/**
	 * Get the path to the framework root
	 * @return string
	 */
	public function getRootPath()	{
		return $this->rootPath;
	}
	
	/**
	 * Get the path to the frameworks var directory.
	 * 
	 * Will create the directory if it does not exist
	 * 
	 * @return string
	 */
	public function getVarPath()	{
		$varPath = $this->getRootPath() . '/../var';
		
		//create if not there
		if (!file_exists($varPath))	{
			mkdir($varPath);
		}
		return $varPath;
	}
	
	/**
	 * Get path to where site specific classes should be stored.
	 * 
	 * @return string
	 */
	public function getSitePath()	{
		$sitePath = $this->getRootPath() . '/../site';
		
		//create if not there
		if (!file_exists($sitePath))	{
			mkdir($sitePath);
		}
		return $sitePath;
	}
	
	/**
	 * Initialise the class autoloader
	 * 
	 */
	public function setupAutoloader()	{
		$this->loadSourceFile('Autoloader', 'Autoloader.php');
		$this->loadSourceFile('Autoloader', 'IAutoloader.php');
		$this->loadSourceFile('Autoloader', 'IncludePathAutoloader.php');
		
		$includeAL = new IncludePathAutoloader(array($this->getRootPath(), $this->getSitePath()));
		$this->includeAutoloader = $includeAL;
		
		Autoloader::setVarDir($this->getVarPath() . '/autoloader');
		Autoloader::addAutoloader($includeAL);
		
		$a = Autoloader::setupAutoloader();
	}
	
	/**
	 * Load a specific file from the framework.
	 * 
	 * Use the autoload feature instead of this for most cases.
	 * 
	 * @param $packageName
	 * @param $fileName
	 */
	public function loadSourceFile($packageName, $fileName)	{
		$fullpath = $this->getRootPath() . '/' . $packageName . '/' . $fileName;
		if (file_exists($fullpath))	{
			return require_once($fullpath);
		}
		
		throw new RuntimeException('File not found for inclusion: ' . $fullpath);
		return;
	}
	
	/**
	 * Load the framework config
	 */
	public function setupConfig()	{
		$this->config = new ConfigContainer();
		
		$this->config->addConfig('rootPath', $this->getRootPath());
		
		try	{
			$configLoader = new ConfigLoader($this->config, $this->getRootPath() . '/config.php');
			$configLoader->loadConfig();
		} catch(Exception $e)	{
			//base config not found
		}
		
		if (file_exists($this->getSitePath()))	{
			try	{
				$siteConfigLoader = new ConfigLoader($this->config, $this->getSitePath() . '/config.php');
				$siteConfigLoader->loadConfig();
			} catch (Exception $e)	{
				//ignore the exception if site config not found - will use default config
			}
		}
	}
	
	/**
	 * Setup database connections as specified in the config
	 * 
	 */
	public function setupDB()	{
		$dbSettings = $this->config->getConfig('db');
		if (is_array($dbSettings))	{
			foreach($dbSettings as $name => $aDB)	{
				$classname = $aDB['type'] . 'DBConnection';
				if (class_exists($classname))	{
					$dbConn = new $classname($aDB['host'], $aDB['username'], $aDB['password'], $aDB['schema']);
					if (!$name)	{
						$name = 'default';
					}
					Model::addDatabase($name, $dbConn);
				}
			}
		}
	}
	
	/**
	 * Initialises the model
	 */
	public function setupModel()	{
		//add model dir to autoloader
		$modelDir = $this->getRootPath() . $this->getConfig('modelDir');
		
		$modelAL = Model::getAutoloader();
		$modelAL->setModelDir($modelDir);
		
		Autoloader::addAutoloader($modelAL);
		
		Model::generateValidEntityNamesFromDB();
	}
	
	
	/**
	 * Get the entire framework's config container or a single config value.
	 * 
	 * @return ConfigContainer
	 */
	public function getConfig($key = null)	{
		if (!isset($this->config))	{
			$this->setupConfig();
		}
		if ($key)	{
			return $this->config->getConfig($key);
		} else {
			return $this->config;
		}
	}
	
	/**
	 * Get a view from the currently requested URL
	 * 
	 * @return View
	 */
	public function getViewFromCurrentURL()	{
		
		
		$request = new Request($this->getConfig('baseURL'), $_SERVER);
		
		$urlMap = $this->getURLMap();
		
		$targetName = $urlMap->getTargetNameFromPath($request->getRequestedPath());
		
		if ($targetName == URLMap::UNKNOWN_TARGET_NAME)	{
			$targetName = 'HTTP404';
		}

		$viewFactory = new ViewFactory();
		
		$resourceContainer = $this->getViewResourceContainer();
		$resourceContainer->addResource('smarty', $this->getSmarty());
		$resourceContainer->addResource('request', $request);
		
		$view = $viewFactory->getViewByTargetName($targetName, $resourceContainer);
		
		

		return $view;
	}
	
	/**
	 * 
	 * @return ViewResourceContainer
	 */
	public function getViewResourceContainer()	{
		if (!isset($this->viewResourceContainer))	{
			$this->viewResourceContainer = new ViewResourceContainer();
		}
		return $this->viewResourceContainer;
	}
	
	/**
	 * Get the smarty object to use for the request.
	 * 
	 * @return Smarty
	 */
	public function getSmarty()	{
		require_once('Smarty.class.php');
		$smarty = new Smarty();
		$smarty->template_dir = realpath($this->getRootPath() . $this->getConfig('smartyTemplateDir'));
		$smarty->compile_dir = realpath($this->getRootPath() . $this->getConfig('smartyCompileDir'));
		$smarty->cache_dir = realpath($this->getRootPath() . $this->getConfig('smartyCacheDir'));
		$smarty->config_dir = realpath($this->getRootPath() . $this->getConfig('smartyConfigDir'));
		return $smarty;
	}

	/**
	 * Get the completed URL map for the site
	 * @return URLMap
	 */
	public function getURLMap()	{
		$urlMap = new URLMap();
		
		//TODO get these from a datasource
		$urlMap->addURL('/admin', 'Admin');
		$urlMap->addURL('/', 'Home');
		
		return $urlMap;
	}
}
?>